package com.beeasy.hzbpm.ctrl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import com.beeasy.hzbpm.bean.Log;
import com.beeasy.hzbpm.filter.Auth;
import com.github.llyb120.nami.core.MultipartFile;
import com.github.llyb120.nami.ctrl.Ctrl;
import com.github.llyb120.json.Arr;
import com.github.llyb120.json.Json;
import com.github.llyb120.json.Obj;
import com.github.llyb120.nami.server.Response;
import com.mongodb.client.model.UpdateOptions;
import org.bson.Document;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

import static com.beeasy.hzbpm.bean.MongoService.db;
import static com.github.llyb120.json.Json.*;

public class menu extends Ctrl {

    public void changeOpen(){
        db.getCollection("menu").updateOne(
            o("id", $get.s("id")).toBson(),
            o(
                "$set", o(
                    "open", $get.s("open")
                )
            ).toBson()
        );
    }

    public Object save(){
        String id = $post.s("id", "");
        String pid = $post.s("pid", "");
        //不能有children
        $post.remove("children");
        if($post.s("text", "").isEmpty()){
            $post.put("text", $post.s("name"));
        }
        if(pid.isEmpty()){
            $post.put("pid", null);
        }
        //菜单名必须唯一
        String name = $post.ss("name").trim();
        if(db.getCollection("menu").countDocuments(bo(
            "id", o("$ne", id),
            "name", name
        )) > 0){
            error("已经有相同名的菜单");
        }
        if(id.isEmpty()){
            $post.put("id", IdUtil.objectId());
            db.getCollection("menu").insertOne($post.toBson());
            Log.log("新建菜单【%s】", $post.s("name", ""));
        } else {
            db.getCollection("menu").replaceOne(
                o("id", id).toBson(),
                $post.toBson()
            );
            Log.log("编辑菜单【%s】", $post.s("name", ""));
        }
        return true;
    }


    public void del(){
        Document doc = db.getCollection("menu").findOneAndDelete(o("id", $get.s("id")).toBson());
        Log.log("删除菜单【%s】", doc.getString("name"));
    }

    public MultipartFile backup() throws IOException {
        List<Object> list = db.getCollection("menu").find().into(a())
            .stream()
            .peek(e -> ((Map)e).remove("_id"))
            .collect(Collectors.toList());
        File temp = File.createTempFile("aaa", "bbb");
        FileUtil.writeUtf8String(Json.stringify(list), temp);
        return new MultipartFile("menu-"+ DateUtil.formatDate(new Date()) +".data", temp, true);
    }

    public void restore(MultipartFile file) {
        try (
            InputStream is = (file.openInputStream());
        ) {
            Arr arr = Json.parse(IoUtil.readBytes(is));
            db.getCollection("menu").deleteMany(o().toBson());
            db.getCollection("menu").insertMany(arr.toBson());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Object menu(){
//        response.setHeader("Content-Type", "application/javascript");
        Obj userInfo = db.getCollection("user").find(o(
              "id", Auth.getUid()
        ).toBson()).into(a()).o(0);
        if(userInfo.i("su") == 1){
            // 管理员返回所有
            String type = $get.s("type", "scope");
//        StringBuilder sb = new StringBuilder();
            Arr arr = db.getCollection("menu")
                    .aggregate(a(
                            !type.equals("scope") ?  undefined : o("$match", o("open", "y")),
                            o("$project", o("_id", 0))
                    ).toBson())
                    .into(a());
            Arr d = tree((List)arr, "pid", "id");
            return d;
//        sb.append("var _menu = ");
//        sb.append(Json.stringify(d));
//        sb.append(";");
//        return sb.toString();
        }else{
            // 查询角色

            ArrayList list = ((ArrayList)userInfo.get("orgs"));

            ArrayList role = (ArrayList) list.stream()
                    .filter(item -> ((Document)item).get("type").equals("ROLE"))
                    .collect(Collectors.toList());
            if(role.size() == 0){
                return null;
            }

            ArrayList roleList = (ArrayList) role.stream()
                    .map(key -> ((Document) key).get("id"))
                    .collect(Collectors.toList());

            Arr menuList = db.getCollection("roleMenuAuthority")
                    .aggregate(a(
                            o("$match", o("rid", o("$in",aaa(roleList)))),
                            o("$project", o("_id", 0,"rid",0))
                    ).toBson())
                    .into(a());
            if(menuList.size() == 0){
                return null;
            }
            Arr allowList = a();
            for (int i = 0; i < menuList.size(); i++) {
                Obj item = ooo(menuList.get(i));
                allowList.addAll(aaa(item.get("list")));
            }

//            Arr arr = db.getCollection("menu")
//                    .aggregate(a(
//                            o("$match", o("open", "y")),
//                            o("$graphLookup",o(
//                                    "from","menu",
//                                    "startWith","$id",
//                                    "connectFromField","id",
//                                    "connectToField","pid",
//                                    "as","children"
//                            )),
//                             o("$match", o(
//                                     "children",o(
//                                             "$elemMatch",o(
//                                                     "id",o("$in",allowList)
//                                             )
//                                     )
//                             )),
////                            o("$match", o("open", "y","id",o("$in",allowList))),
//
//                            o("$project", o("_id", 0))
//                    ).toBson())
//                    .into(a());
            Arr arr = db.getCollection("menu")
                    .aggregate(a(
                            o("$match", o("open", "y","id",o("$in",allowList))),
                            o("$project", o("_id", 0))
                    ).toBson())
                    .into(a());
            Arr d = tree((List)arr, "pid", "id");

            return d;
        }


    }

    /**
     * 角色配置权限
     *
     * */
    public void menuAuthority(){
        Arr list = Json.parse($post.s("list","{}"));
        Obj bson = o(
                "$set",o(
                        "rid",$post.s("id",null),
                        "list",list
                )

        );
        Obj condition = o(

                "rid",$post.s("id",null)
        );
        // 存在则更新，不存在就插
        UpdateOptions uo = new UpdateOptions();
        uo.upsert(true);

        db.getCollection("roleMenuAuthority").updateOne(condition.toBson(),bson.toBson(),uo);
    }
    public Object getRoleAllowMenu(){
        String rid = $get.s("id",null);
        Obj list = getRoleMenu(rid);

        return list;
    }
    /**
     * 获取 角色权限列表
     * */
    private Obj getRoleMenu(String rid){
        Obj condition = o(
            "rid",rid
        );
        List<Obj> list = db.getCollection("roleMenuAuthority").find(condition.toBson()).into(a()).oa();
        if(list.size() == 0){
            return o("list",null);
        }

        return list.get(0);
    }

    public static Arr tree(List list, String parentKey, String childKey) {
        Map map = new HashMap();
        for (Object _map1 : list) {
            Map map1 = (Map) _map1;
            Object key = map1.get(childKey);
            if (key == null) {
                continue;
            }
            map.put(key, map1);
        }
        Arr ret = a();
        for (Object _map1 : list) {
            Map map1 = (Map) _map1;
            Object key = map1.get(parentKey);
            if (key == null) {
                ret.add(map1);
                continue;
            }
            Map par = (Map) map.get(key);
            if (par == null) {
                continue;
            }
            List<Map> child = (List<Map>) par.get("children");
            if (child == null) {
                child = new ArrayList<>();
                par.put("children", child);
            }
            child.add(map1);
        }
        for (Object _map1 : list) {
            Map map1 = (Map) _map1;
            List<Map> child = (List<Map>) map1.get("children");
            if (child == null) {
                continue;
            }
            child.sort((a, b) -> {
                int aa = ooo(a).ii("sort");
                int bb = ooo(b).ii("sort");
                return Integer.compare(aa,bb);
            });
        }
        ret.sort((a,b) -> {
            int aa = ooo(a).ii("sort");
            int bb = ooo(b).ii("sort");
            return Integer.compare(aa,bb);
        });
        return ret;
    }
}
